package ca.cbc.msb.mq;

import javax.jms.JMSException;
import javax.naming.NamingException;

import ca.cbc.msb.persistence.ProcessingStatusPersistence;
import ca.cbc.msb.util.ProgressReport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ca.cbc.medialib.entity.Media;
import ca.cbc.medialib.entity.enums.ProcessStatus;
import ca.cbc.medialib.exception.ThePlatformObjectNotFoundException;
import ca.cbc.medialib.service.MediaService;
import ca.cbc.medialib.util.ApplicationContextUtil;
import ca.cbc.msb.entity.MSBMessage;
import ca.cbc.msb.entity.MSBNotification;
import ca.cbc.msb.enums.NotificationType;
import ca.cbc.msb.enums.QueueEnum;
/**
 *  JMS implementation of MessageHandler for processing MSBNotification message.
 * dispatch messages to new/deleted/change message queue.
 * 
 * @author w. w
 */
public class NotificationMessageHandler implements MessageHandler {

	private MediaService ms;
	private ProcessingStatusPersistence processingStatusPersistence;

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	public NotificationMessageHandler() {
		ms = new MediaService();
		processingStatusPersistence = ApplicationContextUtil.instance.getApplicationContext().getBean(ProcessingStatusPersistence.class);
	}
	
	@Override
	public void handle(MSBMessage message, MessageUtil messageUtil) throws NamingException,
			JMSException {
		MSBNotification notification = message.getNotification();
		logger.debug(">>>NewNotificationMessage received ({}), type is {}", message, message.getNotification().getType());
				
		/*
		 * Dealing with processing flag here
		 */
		try {
			if(!processingStatusPersistence.addProcessingFlag(message)) {	//message processing
				logger.info("Message({}) is Progressing, rolled back", message);
	            ProgressReport.instance.statusReport(message, " Submitted or changed while Processing, message rolled back to be processed later");
	            messageUtil.rollback();
	            return;
			} else {				
				messageUtil.commit(); //commit receive notification message
				Media media = null;
				try {
					media = ms.getMediaWithReleaseId(message.getNotification().getReleaseId());
					message.setMedia(media); //<--set media here
			        if(!media.getDelivery().equals("streaming")){
			        	ProgressReport.instance.statusReport(message, "Release is not Streaming, Process Aborted");
			        	logger.info("Release({}) is not Streaming, Process Aborted", message);
			        	processingStatusPersistence.removeProcessingFlag(message);
			        	return;
			        }
				} catch (ThePlatformObjectNotFoundException e) {
					logger.warn("!No media can be found for this notification, it might be deleted...");
					ProgressReport.instance.report("No media found for message {}", message);
					if(message.getNotification().getType() != NotificationType.DeletedRelease){
						logger.info("No media found({}) and it's not delete notification, Process Aborted", message);
						processingStatusPersistence.removeProcessingFlag(message);
						return;
					}
				}
			}
		} catch (Exception e) {
			logger.error("Unkonw error when processing notification, abort further action.", e);
			processingStatusPersistence.removeProcessingFlag(message);
			return;
		}

		
		NotificationType type = notification.getType();
		switch(type){
			case NewRelease:
				processingStatusPersistence.changeProcessingFlag(message, ProcessStatus.NEW_RELEASE);
				messageUtil.submitMessage(QueueEnum.NewReleaseQueue, message);
	            logger.debug("NewReleaseMessage submitted to {}>>>", QueueEnum.NewReleaseQueue);
                ProgressReport.instance.statusReport(message," new Release Processing Started.");
	            break;
			case ChangedMedia:
				processingStatusPersistence.changeProcessingFlag(message, ProcessStatus.CHANGED_RELEASE);
				messageUtil.submitMessage(QueueEnum.ChangeMediaQueue, message);
	            logger.debug("NewChangedMediaMessage submitted to {}>>>", QueueEnum.ChangeMediaQueue);
                ProgressReport.instance.statusReport(message,"Change Processing Started.");
	            break;
			case DeletedRelease:
				processingStatusPersistence.changeProcessingFlag(message, ProcessStatus.DELETE_RELEASE);
				messageUtil.submitMessage(QueueEnum.DeleteReleaseQueue, message);
	            logger.debug("NewDeleteReleaseMessage submitted to {}>>>", QueueEnum.DeleteReleaseQueue);
	            ProgressReport.instance.report(" {} Delete Processing Started.", message.getNotification().getReleaseId());
	            break;
		    default:
	            logger.error("!!!NewNotificationMessage type is unknown {}>>>", type );
	            processingStatusPersistence.removeProcessingFlag(message);
	            break;
		}
	    messageUtil.commit(); //commit for submit message
	}
}
